home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 June: Reference Library / Dev.CD Jun 94.toast / Periodicals / develop / develop Issue 11 / develop 11 code / The NetWork Project / Examples (Sources) / UDPTransport.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-15  |  12.0 KB  |  380 lines  |  [TEXT/MPS ]

  1. /*    UDPTransport
  2.  
  3.     © Copyright 1991 Joachim Lindenberg, Karlsruhe. All rights reserved.
  4.     
  5.     This program illustrates how you can write your own transport systems.
  6.     
  7.     Created :    Jan 18, 1991
  8.     Revised :    Jan 20, 1991 : added menu handling code, removed SIOW stuff.
  9.                 Jan 24, 1991 : added callback in notification. fixed abort sequences.
  10.                                added rudimentary DA support and about.
  11.                 Feb  5, 1991 : added alert warning about terminating UDP if there are
  12.                                other NetWork applications.
  13.                 Apr 28, 1991 : modifications for new TransportRecord, domain not yet implemented
  14.                 May 30, 1991 : modifications to use defined error codes.
  15.                 May 31, 1991 : modified to drop into debugger if aborting active message.
  16.                 
  17.     This transport is limited in several ways:
  18.     - it doesn´t support messages larger than 8KB (a limitation of .MacTCP)
  19.     - it doesn´t support split information transfer, all data is packed into one UDP datagram
  20.     - cannot abort UDP transfers in progress.
  21.     
  22.     Also, the user interface is akward at best.
  23. */
  24.  
  25. #include <Stdio.h>
  26. #include <NetWork.h>
  27. #include <Devices.h>
  28. #include <SegLoad.h>
  29. #include <ToolUtils.h>
  30. #include <MacTCPCommonTypes.h>
  31. #include <UDPPB.h>
  32. #include <QuickDraw.h>
  33. #include <Events.h>
  34. #include <Menus.h>
  35. #include <Memory.h>
  36. #include <Windows.h>
  37. #include <Fonts.h>
  38. #include <Dialogs.h>
  39. #include <TextEdit.h>
  40. #include <Desk.h>
  41.  
  42. #define UDPMaxSize 8000
  43. #define MemReserve 16384
  44.  
  45. short UDPPort = 40;
  46. long HeaderSize = 40;
  47.  
  48. #define HeaderOffset (sizeof (long))
  49.  
  50. short MacTCPRefNum; StreamPtr UDPStream;
  51.  
  52. typedef struct UDPMsgRec {
  53.     MsgRec MsgRec;
  54.     UDPiopb ParamBlock;
  55.     wdsEntry WDS [5];
  56. } UDPMsgRec, *UDPMsgPtr;
  57.  
  58. pascal void CallBack (MsgPtr Msg, void *Proc) = {0x205F, 0x4e90};
  59.  
  60. void UDPCompletion (struct UDPiopb *iopb)
  61. {
  62.     MsgPtr Msg;
  63.     Msg = (MsgPtr) (((long) iopb) - sizeof (MsgRec));
  64.     CallBack (Msg, (void*) Msg->MsgTrpPtr->TransportAttnRtn);
  65. }
  66.  
  67. void UDPRcvAbort (UDPMsgPtr Msg)
  68. {
  69.     if (Msg->ParamBlock.ioResult <= 0) {
  70.         if (Msg->ParamBlock.csParam.receive.rcvBuffLen) {
  71.             Msg->ParamBlock.csCode = UDPBfrReturn;
  72.             Msg->ParamBlock.ioCompletion = NULL;
  73.             PBControl ((ParmBlkPtr) &(Msg->ParamBlock), false);
  74.             Msg->ParamBlock.csParam.receive.rcvBuffLen = 0;
  75.         }
  76.         Msg->MsgRec.MsgResult = eAbortMsg;
  77.     }
  78.     else {
  79.         ProgramBreak ("\paborting active receive");
  80.         while (Msg->ParamBlock.ioResult < 0) ; /* Sorry, active wait */
  81.     }
  82. }
  83.  
  84. void UDPListen (UDPMsgPtr Msg)
  85. {
  86.     OSErr err;
  87.     Msg->ParamBlock.csCode = UDPRead; 
  88.     Msg->ParamBlock.ioCRefNum = MacTCPRefNum; 
  89.     Msg->ParamBlock.udpStream = UDPStream;
  90.     Msg->ParamBlock.csParam.receive.timeOut = 2;
  91.     Msg->ParamBlock.csParam.receive.secondTimeStamp = 0;
  92.     Msg->ParamBlock.ioCompletion = (UDPIOCompletionProc) UDPCompletion;
  93.     Msg->ParamBlock.csParam.receive.userDataPtr = (Ptr) Msg;
  94.     err = PBControl ((ParmBlkPtr) &(Msg->ParamBlock), true);
  95. }
  96.  
  97. void UDPListenCompletion (UDPMsgPtr Msg)
  98. {
  99.     if ((Msg->ParamBlock.csParam.receive.rcvBuffLen) && (* ((long*) Msg->ParamBlock.csParam.receive.rcvBuff) == HeaderSize)) {
  100.         BlockMove ((void*) ( (long) Msg->ParamBlock.csParam.receive.rcvBuff + HeaderOffset), 
  101.             (void*) &(Msg->MsgRec.MsgSource), HeaderSize);
  102.         Msg->MsgRec.MsgResult = Msg->ParamBlock.ioResult;
  103.         if ((Msg->MsgRec.MsgResult == 0) && (Msg->MsgRec.MsgSource.a == Msg->MsgRec.MsgTrpPtr->TransportAddr)) 
  104.             Msg->MsgRec.MsgResult = eLoopback;
  105.     }
  106.     else Msg->MsgRec.MsgResult = eVersion;
  107. }
  108.  
  109. void UDPGet (UDPMsgPtr Msg)
  110. {
  111.     BlockMove ((void*) ((long) Msg->ParamBlock.csParam.receive.rcvBuff + HeaderOffset + 
  112.         * (long*) Msg->ParamBlock.csParam.receive.rcvBuff),
  113.             (void*) Msg->MsgRec.MsgPrioPtr, (Msg->MsgRec.MsgPrioSize));
  114.     Msg->MsgRec.MsgResult = noErr;
  115. }
  116.  
  117. void UDPAccept (UDPMsgPtr Msg)
  118. {
  119.     BlockMove ((void*) ((long) Msg->ParamBlock.csParam.receive.rcvBuff + HeaderOffset + * (long*) Msg->ParamBlock.csParam.receive.rcvBuff
  120.              + ((MsgPtr) ((long) Msg->ParamBlock.csParam.receive.rcvBuff + HeaderOffset))->MsgPrioSize),
  121.             (void*) Msg->MsgRec.MsgCorePtr, (Msg->MsgRec.MsgCoreSize));
  122.     Msg->MsgRec.MsgResult = noErr;
  123. }
  124.  
  125. void UDPPostCompletion (UDPMsgPtr Msg)
  126. {
  127.     Msg->MsgRec.MsgResult = Msg->ParamBlock.ioResult;
  128. }
  129.  
  130. void UDPPost (UDPMsgPtr Msg)
  131. {
  132.     int wdscount = 0;
  133.     if (HeaderSize + Msg->MsgRec.MsgPrioSize + Msg->MsgRec.MsgCoreSize + sizeof (HeaderSize) > UDPMaxSize) 
  134.         Msg->MsgRec.MsgResult = eSizeLimit;
  135.     else {
  136.         Msg->WDS [wdscount].length = sizeof (HeaderSize); 
  137.         Msg->WDS [wdscount].ptr = (Ptr) &HeaderSize;
  138.         if (Msg->WDS [wdscount].length) ++wdscount;
  139.         Msg->WDS [wdscount].length = HeaderSize; 
  140.         Msg->WDS [wdscount].ptr = (Ptr) & (Msg->MsgRec.MsgSource);
  141.         if (Msg->WDS [wdscount].length) ++wdscount;
  142.         Msg->WDS [wdscount].length = Msg->MsgRec.MsgPrioSize; 
  143.         Msg->WDS [wdscount].ptr = (Ptr) Msg->MsgRec.MsgPrioPtr;
  144.         if (Msg->WDS [wdscount].length) ++wdscount;
  145.         Msg->WDS [wdscount].length = Msg->MsgRec.MsgCoreSize; 
  146.         Msg->WDS [wdscount].ptr = (Ptr) Msg->MsgRec.MsgCorePtr;
  147.         if (Msg->WDS [wdscount].length) ++wdscount;
  148.         Msg->WDS [wdscount].length = 0;
  149.         
  150.         Msg->ParamBlock.csCode = UDPWrite; 
  151.         Msg->ParamBlock.ioCRefNum = MacTCPRefNum;
  152.         Msg->ParamBlock.ioCompletion = (UDPIOCompletionProc) UDPCompletion;
  153.         Msg->ParamBlock.udpStream = UDPStream;
  154.         Msg->ParamBlock.csParam.send.remoteHost = Msg->MsgRec.MsgDest.a; /* should be MsgDest */
  155.         Msg->ParamBlock.csParam.send.remotePort = UDPPort;
  156.         Msg->ParamBlock.csParam.send.wdsPtr = (Ptr) & Msg->WDS;
  157.         Msg->ParamBlock.csParam.send.checkSum = 0;
  158.         Msg->ParamBlock.csParam.send.sendLength = 0;
  159.         Msg->ParamBlock.csParam.send.userDataPtr = (Ptr) Msg;
  160.         PBControl ((ParmBlkPtr) &(Msg->ParamBlock), true);
  161.     }        
  162. }
  163.  
  164. void UDPPostAbort (UDPMsgPtr Msg)
  165. {
  166.     if (Msg->ParamBlock.ioResult <= 0) Msg->MsgRec.MsgResult = eAbortMsg;
  167.     else {
  168.         ProgramBreak ("\paborting active send");
  169.         while (Msg->ParamBlock.ioResult < 0) ; /* Sorry, active wait */
  170.     }
  171.  
  172. }
  173.  
  174. pascal void UDPTransport (short cmd, UDPMsgPtr Msg, TransportPtr Trp)
  175. {
  176.     long savedA5 = SetA5 ((long) Trp->TransportVars);
  177.     if (Msg) Msg->MsgRec.MsgCmd |= 1;    /* next call expected is completion */
  178.     switch (cmd) {
  179.         case tListen :             UDPListen (Msg); break;
  180.         case tListen+tTickle :    UDPListenCompletion (Msg); break;
  181.  
  182.         case tGet :             UDPGet (Msg); break;
  183.         case tAccept :             UDPAccept (Msg); break;
  184.  
  185.         case tListen+tTimeout :
  186.         case tListen+tTimeout1 :
  187.         case tListen+tAbort :     
  188.         case tListen+tAbort1 :     
  189.         
  190.         case tGet+tTimeout :
  191.         case tGet+tTimeout1 :
  192.         case tGet+tAbort :        
  193.         case tGet+tAbort1 :        
  194.         
  195.         case tAccept+tTimeout :
  196.         case tAccept+tTimeout1 :
  197.         case tAccept+tAbort :    
  198.         case tAccept+tAbort1 :    UDPRcvAbort (Msg); break;
  199.  
  200.         case tPost :             UDPPost (Msg); break;
  201.         case tPost+tTickle :     UDPPostCompletion (Msg); break;
  202.         
  203.         case tPost+tTimeout :
  204.         case tPost+tTimeout1 :
  205.         case tPost+tAbort :        
  206.         case tPost+tAbort1 :    UDPPostAbort (Msg); break;
  207.  
  208.         default :                if (Msg) Msg->MsgRec.MsgResult = eCmdSequence; /* force error */
  209.     }
  210.     SetA5 (savedA5);
  211. }
  212.  
  213. TransportRecord UDPDescription = {
  214.     NULL,                    /* link to next transport in queue                     */
  215.     UDPTransport,            /* pointer to definition proc                         */
  216.     NULL,                    /* name of transport                                */
  217.     'NetU',                    /* transport protocol (unique) signature            */
  218.     NULL,                    /* transport domain dependent string                */
  219.     0, 1, -2, -1,            /* local and other transport addresses                */
  220.     sizeof (UDPMsgRec),        /* size of MsgRecord for this transport system        */
  221.     0, 0, 0,                /* various counters of listeners                    */
  222.     0,                        /* reserved for future use                            */
  223.     NULL,                    /* private vars, may be longint, ptr, or handle        */
  224.     NULL,                    /* pointer to head of message queue                    */
  225.     NULL                    /* pointer to attn routine (supplied by NetWork)    */
  226. };
  227.  
  228. void ErrorExit (char *s, short err)
  229. {
  230.     if (err) {
  231.         CheckError (s, err);
  232.         ExitToShell ();
  233.     }
  234. }
  235.  
  236. pascal void UDPNotification (StreamPtr udpStream, unsigned short eventCode, TransportPtr Trp, struct ICMPReport *icmpMsg)
  237. {
  238.     if (eventCode == UDPDataArrival) { 
  239.         ++Trp->TransportListensRequested;
  240.         CallBack (NULL, (void*) Trp->TransportAttnRtn);
  241.     }
  242. }
  243.  
  244. OSErr UDPClosePort (void)
  245. {
  246.     UDPiopb ParamBlock; OSErr err;
  247.     ParamBlock.csCode = UDPRelease; ParamBlock.ioCRefNum = MacTCPRefNum;
  248.     ParamBlock.udpStream = UDPStream;
  249.     err = PBControl ((ParmBlkPtr) &ParamBlock, false);
  250.     return (err);
  251. }
  252.  
  253. OSErr UDPOpenPort (void)
  254. {
  255.     UDPiopb ParamBlock; OSErr err;
  256.     ParamBlock.csCode = 15; ParamBlock.ioCRefNum = MacTCPRefNum;
  257.     err = PBControl ((ParmBlkPtr) &ParamBlock, false);
  258.     UDPDescription.TransportAddr = (long) ParamBlock.udpStream;
  259.     UDPDescription.TransportBCAddr = (long) ParamBlock.csParam.create.rcvBuff;
  260.     UDPDescription.TransportBCAddr = (UDPDescription.TransportBCAddr & UDPDescription.TransportAddr)
  261.                             + ~UDPDescription.TransportBCAddr;
  262.     ParamBlock.csCode = UDPCreate; ParamBlock.ioCRefNum = MacTCPRefNum;
  263.     ParamBlock.csParam.create.rcvBuffLen = FreeMem () - MemReserve;
  264.     ParamBlock.csParam.create.rcvBuff = NewPtr (ParamBlock.csParam.create.rcvBuffLen);
  265.     if (ParamBlock.csParam.create.rcvBuff == NULL) ErrorExit ("\pNewPtr", MemError ());
  266.     ParamBlock.csParam.create.notifyProc = (UDPNotifyProc) UDPNotification;
  267.     ParamBlock.csParam.create.localPort = UDPPort;
  268.     ParamBlock.csParam.create.userDataPtr = (Ptr) & UDPDescription;
  269.     err = PBControl ((ParmBlkPtr) &ParamBlock, false);
  270.     UDPStream = ParamBlock.udpStream;
  271.     return (err);
  272. }
  273.  
  274. /*    removing a transport system may cause problems because it provides a service to
  275.     other applications. It is safe to remove, if no other processes are executing,
  276.     and if no messages are pending (Note that though no process is alive, there may
  277.     still be messages pending). 
  278.     
  279.     Testing for other processes doesn´t catch the possibility that the other processes
  280.     might be transport systems as well.
  281. */
  282.  
  283. Boolean NoMoreMessages (void)
  284. {
  285.     MsgPtr p = *UDPDescription.TransportMsgQHead;
  286.     while (p)
  287.         if (p->MsgTrpPtr == &UDPDescription) return (false);
  288.         else p = p->MsgLink;
  289.     return (true);
  290. }
  291.  
  292. Boolean SafeToExit (void)
  293. {
  294.     int e = 0, n = 0; long signature;
  295.     while (e == noErr) {
  296.         e = GetIndProcess (&signature, ++n);
  297.         if ((signature != 0) && (signature != UDPDescription.TransportID)) return (false);
  298.     }
  299.     return (NoMoreMessages ());
  300. }
  301.  
  302. void InitToolBox (void)
  303. {
  304.     MaxApplZone (); MoreMasters ();
  305.     InitGraf(&qd.thePort);             //    {initialize QuickDraw}
  306.     InitFonts ();                    //    {initialize Font Manager}
  307.     InitWindows ();                    //    {initialize Window Manager}
  308.     InitMenus ();                    //    {initialize Menu Manager}
  309.     TEInit ();                         //    {initialize TextEdit}
  310.     InitDialogs(NULL);                //    {initialize Dialog Manager}
  311.     InitCursor ();                     //    {call QuickDraw to make cursor (pointer) an arrow}
  312.  
  313.     SetMenuBar (GetNewMBar (256));
  314.     AddResMenu (GetMHandle (256), 'DRVR');
  315.     DrawMenuBar ();
  316. }
  317.  
  318. void About (void)
  319. {
  320.     Alert (256, NULL);
  321. }
  322.  
  323. void OpenDA (int itemno)
  324. {
  325.     Str255 daname;
  326.     GetItem (GetMHandle (256), itemno, daname);
  327.     OpenDeskAcc (daname);
  328. }
  329.  
  330. Boolean Done = false, FrontMost = true;
  331.  
  332. void DoMenu (long menuselection)
  333. {
  334.     switch (HiWord (menuselection)) {
  335.         case 256 : if (LoWord (menuselection) == 1) About ();
  336.                    else OpenDA (LoWord (menuselection));
  337.                    break;
  338.         case 257 : if (SafeToExit () || (Alert (257, NULL) == 2)) {
  339.                     Done = true;
  340.                     ErrorExit ("\pRemoveTransport", RemoveTransport (&UDPDescription));
  341.                     break;
  342.                    }
  343.     }
  344.     HiliteMenu (0);
  345. }
  346.  
  347. main ()
  348. {
  349.     Str255 appname; short appref; Handle appparms;
  350.     EventRecord Event; WindowPtr w;
  351.     
  352.     InitToolBox ();
  353.     
  354.     GetAppParms (appname, &appref, &appparms);
  355.     UDPDescription.TransportName = NewString (appname);
  356.     (long) UDPDescription.TransportVars = SetCurrentA5 ();
  357.     
  358.     ErrorExit ("\pInitNetWork", InitNetWork (nullEvent));
  359.     ErrorExit ("\pMacTCP", OpenDriver ("\p.ipp", &MacTCPRefNum));
  360.     ErrorExit ("\pUDPCreate", UDPOpenPort ());
  361.  
  362.     ErrorExit ("\pInstallTransport", InstallTransport (&UDPDescription));
  363.     
  364.     while (!Done || !NoMoreMessages ()) {
  365.         if (WaitNextEvent (everyEvent, &Event, (Done || FrontMost) ? 60 : 0x7fffffff, NULL))
  366.             switch (Event.what) {
  367.                 case mouseDown:    if (FindWindow (Event.where, &w) == inMenuBar)
  368.                                     DoMenu (MenuSelect (Event.where));
  369.                                 break;
  370.                 case keyDown:    if (Event.modifiers & cmdKey) 
  371.                                     DoMenu (MenuKey (Event.message & charCodeMask));
  372.                                 break;
  373.                 case app4Evt : if (Event.message & 0xff000000 == 0x01000000)
  374.                                     FrontMost = Event.message & 0x1;
  375.             }
  376.     }
  377.     ErrorExit ("\pUDPRelease", UDPClosePort ());
  378.     ErrorExit ("\pExitNetWork", ExitNetWork ());
  379. };
  380.